/* #include <inttypes.h> */

#include "../include/clientEntrance.h"
#include <sys/sendfile.h>
typedef struct train_s{
    int type;
    int length;
    char data[1000];
}train_t;

int get_store_path(char buf[])
{
    strcpy(buf,"/home/");
    uid_t uid = getuid();
    struct passwd *pwd = getpwuid(uid);
    strcat(buf,pwd->pw_name);
    strcat(buf,"/clientStore/");
    if(access(buf,F_OK) != 0)
    {
        mkdir(buf,0777);
    }
    /* printf("%s\n",buf); */
    return 0;
}
int recvn(int sockfd,void *buf,int length){
    int total=0;
    char * p=(char *)buf;
    while(total<length){
        int ret=recv(sockfd,p+total,length-total,0);
        total+=ret;
        printf("\r%2.4lf%%",total * 1.0 / length * 100);
    }
    printf("\r");
    return 0;
}

/* int c_recv_download(int sockfd,char *filename){ */
int c_recv_download(int sockfd,char *filename){
    char path[1024];
    get_store_path(path);
    printf("文件存放的目录:%s\n",path);
    strcat(path,filename);
    /* printf("------\n"); */
    train_t train;
    int size=0;
    if(access(path,F_OK)==0){ // 文件存在就断点续传
        printf("触发断点续传\n");
        train.type=11;
        send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);

    // 执行断点续传逻辑
        // 发文件名
        train.type=0;
        train.length=strlen(filename)+1;

        memcpy(train.data,filename,train.length);
        send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
        send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(sockfd,train.data,train.length,MSG_NOSIGNAL);

        // 发断点文件大小
        struct stat statbuf;
        stat(path,&statbuf);
        size=statbuf.st_size;
        printf("size=%d\n",size);
        train.type=0;
        train.length=sizeof(size);
        memcpy(train.data,&size,train.length);
        /* memcpy(train.data,&size,sizeof(size)); */
        send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
        send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(sockfd,train.data,train.length,MSG_NOSIGNAL);

        // 收实际文件大小
        int filesize=0;
        recvn(sockfd,&train.type,sizeof(train.type));
        recvn(sockfd,&train.length,sizeof(train.length));
        recvn(sockfd,train.data,train.length);
        memcpy(&filesize,train.data,train.length);
        printf("文件大小为:%d\n",filesize);


        // 收文件
        int fd=open(path,O_RDWR|O_CREAT|O_APPEND,0666);
        if(filesize<10){
            while(1){
                bzero(train.data,sizeof(train.data));
                /* if(train.length==0) break; */
                recvn(sockfd,&train.type,sizeof(train.type));
                recvn(sockfd,&train.length,sizeof(train.length));
                /* if(train.length==0) break; */
                recvn(sockfd,train.data,train.length);
                if(train.length==0) break;
                write(fd,train.data,train.length);
            }
        }else{
            printf("我是mmap\n");
            ftruncate(fd,filesize);
            char *p=(char *)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
            recvn(sockfd,p+size,filesize-size);
            /* write(fd,p,filesize-size); */
            munmap(p,filesize-size);
            /* printf("666\n"); */
        }
        close(fd);
        return 0;
    }else{ //不存在就正常传
        printf("我是普通文件发送\n");
        train.type=22;
        send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
        // 执行正常逻辑
        // 发文件名
        train.type=0;
        train.length=strlen(filename)+1;
        memcpy(train.data,filename,train.length);
        send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
        send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(sockfd,train.data,train.length,MSG_NOSIGNAL);
        printf("train.data=%s\n",train.data);

        // 收实际文件大小
        int filesize=0;
        recvn(sockfd,&train.type,sizeof(train.type));
        recvn(sockfd,&train.length,sizeof(train.length));
        recvn(sockfd,train.data,train.length);
        memcpy(&filesize,train.data,train.length);
        /* printf("filesize=%d\n",filesize); */


        // 收文件
        int total = 0;
        int fd=open(path,O_RDWR|O_CREAT|O_TRUNC,0666);
        if(filesize<10){
            while(1){
                bzero(train.data,sizeof(train.data));    
                /* if(train.length==0) break; */
                recvn(sockfd,&train.type,sizeof(train.type));
                recvn(sockfd,&train.length,sizeof(train.length));
                /* if(train.length==0) break; */
                recvn(sockfd,train.data,train.length);
                if(train.length==0) break;
                write(fd,train.data,train.length);
                // 计算下载进度
                total += train.length;
                printf("\r%2.2lf%%",total * 1.0 / filesize *100);
            }   
        }else{
            printf("我是mmap\n");
            ftruncate(fd,filesize);
            char *p=(char *)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
            recvn(sockfd,p,filesize);
            /* write(sockfd,p,filesize); */
            munmap(p,filesize);
        }
        printf("\n");
        return 0;
    }
    return 0;
}

int c_up(int sockfd,char *filename){
    char path[1024];
    get_store_path(path);
    strcat(path,filename);
    /* printf("------\n"); */
    train_t train;
    // 在这块调用求hash的函数
    /* char hash[]="123"; */ 
    char hash[1024]={0};
    haxi(path,hash);
    /* printf("hash=%s\n",hash); */
    /* printf("filename=%s\n",filename); */
    // 发文件名
    train.type=0;
    train.length=strlen(filename)+1;
    memcpy(train.data,filename,train.length);
    send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
    send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(sockfd,train.data,train.length,MSG_NOSIGNAL);
    // 发hash
    train.type=0;
    train.length=strlen(hash)+1;
    memcpy(train.data,hash,train.length);
    send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
    send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(sockfd,train.data,train.length,MSG_NOSIGNAL);
    /* printf("train.data's hash=%s\n",train.data); */

    // 收flag
    int flag=0;
    recvn(sockfd,&train.type,sizeof(train.type));
    recvn(sockfd,&train.length,sizeof(train.length));
    recvn(sockfd,train.data,train.length);
    memcpy(&flag,train.data,train.length);
    /* printf("flag=%d\n",flag); */
    if(flag==1){
        printf("秒传\n");
        return 0;
    }

    recvn(sockfd,&train.type,sizeof(train.type));
    if(train.type==11){ // 断点续传
        // 收断点文件大小                                            
        int size=0;
        recvn(sockfd,&train.type,sizeof(train.type));
        recvn(sockfd,&train.length,sizeof(train.length));
        recvn(sockfd,train.data,train.length);
        memcpy(&size,train.data,train.length);
        printf("size=%d\n",size);

        // 算实际文件大小
        struct stat statbuf;
        stat(path,&statbuf);
        int filesize=statbuf.st_size;
        /* printf("filesize=%d\n",filesize); */
        train.type=0;
        train.length=sizeof(filesize);
        memcpy(train.data,&filesize,train.length);
        send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
        send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(sockfd,train.data,train.length,MSG_NOSIGNAL);

        // 从断点处开始发文件
        int fd=open(path,O_RDWR);
        lseek(fd,size,SEEK_SET);
        if(filesize<10){
            while(1){
                bzero(train.data,sizeof(train.data));
                int ret=read(fd,train.data,sizeof(train.data));
                train.length=ret;
                train.type=0;
                send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
                send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
                send(sockfd,train.data,train.length,MSG_NOSIGNAL);
                if(ret==0) break;
            }
        }else{
            printf("我是mmap\n");
            sendfile(sockfd,fd,NULL,filesize-size);
            printf("发完了\n");
        }
        return 0;
    }else if(train.type==22){ // 正常上传
        // 算实际文件大小
        struct stat statbuf;
        stat(path,&statbuf);
        int filesize=statbuf.st_size;
        if(filesize > 1000000)
        {
            printf("文件大小为:%.2lfMB\n",filesize * 1.0/1024/1024);
        }
        else
        {
            printf("文件大小为:%.3lfKB\n",filesize * 1.0/1024);
        }
        train.type=0;
        train.length=sizeof(filesize);
        memcpy(train.data,&filesize,train.length);
        send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
        send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(sockfd,train.data,train.length,MSG_NOSIGNAL);


        int fd=open(path,O_RDWR);
        ERROR_CHECK(fd,-1,"open");
        if(filesize<10){
            while(1){                                              
                bzero(train.data,sizeof(train.data));
                int ret=read(fd,train.data,sizeof(train.data));
                /* if(ret==0) break; */
                train.length=ret;
                train.type=0;
                send(sockfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
                send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
                if(ret==0) break;
                send(sockfd,train.data,train.length,MSG_NOSIGNAL);
                /* printf("222222222222\n"); */
            }
        }else{
            printf("传输类型:mmap\n");
            sendfile(sockfd,fd,NULL,filesize);
            /* printf("发完了\n"); */
        }
        /* printf("333333333333333\n"); */
        /* train.length=0; */
        /* send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL); */
        /* close(sockfd); */
        return 0;
    }

    return 0;
}


/* int main(int argc, char *argv[]){ */
/*     // ./client 192.168.18.128 12345 */                                       
/*     ARGS_CHECK(argc,3); */
/*     printf("555\n"); */
/*     int sockfd=socket(AF_INET,SOCK_STREAM,0); */
/*     printf("333\n"); */
/*     struct sockaddr_in addr; */
/*     addr.sin_family=AF_INET; */
/*     addr.sin_port=htons(atoi(argv[2])); */
/*     addr.sin_addr.s_addr=inet_addr(argv[1]); */
/*     printf("444\n"); */
/*     int ret=connect(sockfd,(struct sockaddr *)&addr,sizeof(addr)); */
/*     printf("666\n"); */
/*     ERROR_CHECK(ret,-1,"connect"); */
/*     printf("lll\n"); */
/*     char filename[]="file1"; */
/*     /1* c_recv_download(sockfd,filename); *1/ */
/*     c_up(sockfd,filename); */
/*     /1* transfile(sockfd); *1/ */
/*     close(sockfd); */
/*     return 0; */
/* } */
